package com.lwl.blue.commont.utils;

import com.alibaba.fastjson.JSON;
import com.aliyun.openservices.shade.org.apache.commons.lang3.ArrayUtils;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lwl.blue.commont.base.BizException;
import com.lwl.blue.commont.base.ErrorCode;
import com.lwl.blue.commont.base.JsonResult;
import com.lwl.blue.commont.base.PageParam;
import com.lwl.blue.entity.Users;
import lombok.extern.slf4j.Slf4j;
import org.springframework.transaction.annotation.Transactional;

import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.util.Date;
import java.util.List;

/**
 * <p>
 *
 * </p>
 *
 * @version V0.0.1
 * @date 2020/3/18
 */

@Slf4j
public class CommonService<M extends BaseMapper<T>, T> extends ServiceImpl<M, T> implements ICommonService<T> {


    @Override
    public JsonResult<T> getByIdForRemote(@NotNull Long id) {
        log.info("【通用接口，根据主键查询对象】{},请求参数：{}", "接口请求", id);
        JsonResult<T> result = new JsonResult<T>();
        T obj = super.getById(id);
        if (null != obj) {
            result.success(obj);
        } else {
            result.error("查询对象不存在！");
        }
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public JsonResult<T> insertForRemote(@Valid T entity) {
        log.info("【通用接口，新增数据】{},请求参数：{}", "接口请求", entity);
        JsonResult<T> result = new JsonResult<T>();
        if (null != entity) {
            createWrapper(entity, null, SAVE);
            boolean rsg = super.save(entity);
            if (rsg) {
                result.success("添加成功");
            } else {
                result.error("添加失败！");
            }
        } else {
            result.error("请传入正确参数！");
        }
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public JsonResult<T> updateWithIdForRemote(@Valid T entity) {
        log.info("【通用接口，修改数据】{},请求参数：{}", "接口请求", entity);
        JsonResult<T> result = new JsonResult<T>();
        if (null != entity) {
            createWrapper(entity, null, UPDATE);
            boolean rsg = super.updateById(entity);
            if (rsg) {
                result.success("修改成功");
            } else {
                result.error("修改失败！");
            }
        } else {
            result.error("请传入正确参数！");
        }
        return result;
    }

    @Override
    public JsonResult<IPage<Object>> getPagesForRemote(PageParam<T> pageParam) {
        log.info("【通用接口，分页查询】{},请求参数：{}", "接口请求", pageParam);
        Class<T> entityClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[1];
        QueryWrapper<T> queryWrapper = new QueryWrapper<>();
        //条件构造
        createWrapper(pageParam.getParam(), queryWrapper, PAGE);
        //分页数据
        IPage pageData = super.page(new Page<T>(pageParam.getPageNum(), pageParam.getPageSize()), queryWrapper);
        Object o = SpringContextUtil.getBean(
                (new StringBuilder())
                        .append(Character.toLowerCase(entityClass.getSimpleName().charAt(0)))
                        .append(entityClass.getSimpleName().substring(1)).toString() + PAGE_VO
        );
        if (o != null && pageData.getRecords() != null && pageData.getRecords().size() > 0) {
            pageData.setRecords(JSON.parseArray(JSON.toJSONString(pageData.getRecords()), o.getClass()));
        }
        return new JsonResult<IPage<Object>>().success(pageData);
    }

    @Override
    public QueryWrapper<T> createQueryWrapper(Object obj) {
        QueryWrapper<T> queryWrapper = new QueryWrapper<T>();
        createWrapper(obj, queryWrapper, PAGE);
        return queryWrapper;
    }

    /**
     * <p>
     * 条件构造
     * </p>
     *
     * @author <a href="mailto:yangyanrui@yidianlife.com">xiaoyang</a>
     * @version V0.0.1
     * @date 2019年08月27日
     */
    protected void createWrapper(Object obj, QueryWrapper<T> queryWrapper, int type) {
        if (obj == null) {
            return;
        }
        Class<? extends Object> clazz = obj.getClass();
        Field[] fields = clazz.getDeclaredFields();
        if (fields != null) {
            // 判断条件构造类型类型
            switch (type) {
                case PAGE:
                    // 分页
                    pageWrapper(obj, fields, clazz, queryWrapper);
                    break;
                case SAVE:
                    // 创建 新增
                case UPDATE:
                    // 修改
                    saveAndUpdateWrapper(fields, obj, type);
                    break;
                default:
            }
        }
    }

    /**
     * <p>
     * 分页查询条件构造
     * </p>
     *
     * @author <a href="mailto:yangyanrui@yidianlife.com">xiaoyang</a>
     * @version V0.0.1
     * @date 2019年08月27日
     */
    protected void pageWrapper(Object obj, Field[] fields, Class<? extends Object> clazz, QueryWrapper<T> queryWrapper) {
        boolean idFlag = false;
        for (Field field : fields) {
            if (!field.isAccessible()) {
                field.setAccessible(true);
            }
            if (Modifier.isFinal(field.getModifiers()) || Modifier.isStatic(field.getModifiers())) {
                continue;
            }
            try {
                Object dstObject = new PropertyDescriptor(field.getName(), clazz).getReadMethod().invoke(obj);
                if (DEL_FLAG.equals(field.getName())) {
                    // 存在逻辑删除 默认不显示已删除的。
                    if (dstObject != null && !"".equals(dstObject)) {
                        queryWrapper.eq(com.baomidou.mybatisplus.core.toolkit.StringUtils.camelToUnderline(field.getName()), dstObject);
                    } else {
                        queryWrapper.eq(com.baomidou.mybatisplus.core.toolkit.StringUtils.camelToUnderline(field.getName()), 0);
                    }
                    continue;
                }
                if (dstObject == null || "".equals(dstObject)) {
                    continue;
                }
                boolean flag = field.isAnnotationPresent(TableField.class);
                if (flag) {
                    TableField tableField = field.getAnnotation(TableField.class);
                    if (!tableField.exist()) {
                        // 非数据库参数
                        if (PARAM_ASC.equals(field.getName())) {
                            // 正序参数
                            if (dstObject != null && dstObject instanceof String[]) {
                                String[] strings = (String[]) dstObject;
                                for (int i = 0; i < strings.length; i++) {
                                    strings[i] = com.baomidou.mybatisplus.core.toolkit.StringUtils.camelToUnderline(strings[i]);
                                }
                                queryWrapper.orderByAsc(strings);
                            }
                        }
                        if (PARAM_DESC.equals(field.getName())) {
                            // 倒序参数
                            if (dstObject != null && dstObject instanceof String[]) {
                                String[] strings = (String[]) dstObject;
                                for (int i = 0; i < strings.length; i++) {
                                    strings[i] = com.baomidou.mybatisplus.core.toolkit.StringUtils.camelToUnderline(strings[i]);
                                }
                                ArrayUtils.addAll(strings, ID.split(","));
                                queryWrapper.orderByDesc(strings);
                                idFlag = true;
                            }
                        }
                        if (ID_BATCH.equals(field.getName()) && dstObject instanceof List) {
                            List<Long> list = (List<Long>) dstObject;
                            queryWrapper.in(ID, list);
                        }
                        // 区间时间判断
                        if (dstObject instanceof Date) {
                            if (field.getName().toLowerCase().endsWith(START)) {
                                queryWrapper.ge(com.baomidou.mybatisplus.core.toolkit.StringUtils.camelToUnderline(field.getName()).replaceAll(_START, ""), (Date) dstObject);
                            }
                            if (field.getName().toLowerCase().endsWith(END)) {
                                queryWrapper.le(com.baomidou.mybatisplus.core.toolkit.StringUtils.camelToUnderline(field.getName()).replaceAll(_END, ""), (Date) dstObject);
                            }
                        }
                        continue;
                    }
                }
                if (dstObject instanceof Date) {
                    // 处理时间条件
                    if (field.getName().toLowerCase().endsWith(START)) {
                        if (dstObject != null && !"".equals(dstObject)) {
                            queryWrapper.ge(com.baomidou.mybatisplus.core.toolkit.StringUtils.camelToUnderline(field.getName()), (Date) dstObject);
                        }
                    } else if (field.getName().toLowerCase().endsWith(END)) {
                        if (dstObject != null && !"".equals(dstObject)) {
                            queryWrapper.le(com.baomidou.mybatisplus.core.toolkit.StringUtils.camelToUnderline(field.getName()), (Date) dstObject);
                        }
                    }
                    continue;
                }
                queryWrapper.eq(com.baomidou.mybatisplus.core.toolkit.StringUtils.camelToUnderline(field.getName()), dstObject);
            } catch (IntrospectionException e) {
                throw new BizException(ErrorCode.SYS_EXCEPTION.getCode(), "分页通用接口，条件构造封装报错！", e);
            } catch (IllegalAccessException e) {
                throw new BizException(ErrorCode.SYS_EXCEPTION.getCode(), "分页通用接口，条件构造封装报错！", e);
            } catch (InvocationTargetException e) {
                throw new BizException(ErrorCode.SYS_EXCEPTION.getCode(), "分页通用接口，条件构造封装报错！", e);
            }
        }
        if (!idFlag) {
            //  固定需要 id 倒序条件
            queryWrapper.orderByDesc(ID);
        }


    }

    /**
     * <p>
     * 新增 / 修改 条件构造
     * </p>
     *
     * @author <a href="mailto:yangyanrui@yidianlife.com">xiaoyang</a>
     * @version V0.0.1
     * @date 2019年08月27日
     */
    protected void saveAndUpdateWrapper(Field[] fields, Object obj, int type) {
        Users userInfo = CurrentUser.getUserInfo();
        for (Field field : fields) {
            if (!field.isAccessible()) {
                field.setAccessible(true);
            }
            if (Modifier.isFinal(field.getModifiers()) || Modifier.isStatic(field.getModifiers())) {
                continue;
            }
            boolean flag = field.isAnnotationPresent(TableField.class);
            if (flag) {
                TableField tableField = field.getAnnotation(TableField.class);
                if (!tableField.exist()) {
                    // 非数据库参数
                    continue;
                }
            }
            try {
                switch (type) {
                    case SAVE:
                        // 判断参数名
                        if (CREATE_ID.equals(field.getName())) {
                            field.set(obj, userInfo.getId());
                        }
                        if (CREATE_NAME.equals(field.getName())) {
                            field.set(obj, userInfo.getUserName());
                        }
                        if (CREATE_TIME.equals(field.getName())) {
                            field.set(obj, new Date());
                        }
                        break;
                    case UPDATE:
                        // 判断参数名
                        if (UPDATE_ID.equals(field.getName())) {
                            field.set(obj, userInfo.getId());
                        }
                        if (UPDATE_NAME.equals(field.getName())) {
                            field.set(obj, userInfo.getUserName());
                        }
                        if (UPDATE_TIME.equals(field.getName())) {
                            field.set(obj, new Date());
                        }
                        break;
                    default:
                }
            } catch (IllegalAccessException e) {
                throw new BizException(ErrorCode.SYS_EXCEPTION.getCode(), "通用接口，新增/修改 条件构造封装报错！", e);
            }
        }
    }
}
